/* 
 * Shuriken is the legal property of its developers. Please refer to the
 * COPYRIGHT file distributed with this
 * source distribution.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

using System;
using System.Drawing; 
using System.Runtime.InteropServices;

namespace Shuriken.Core.Shell
{
    /// <summary>
    /// Wrapper around the Shell Image list 
    /// </summary>
    public class SystemImageList
    {
        #region Dll imports

        public const int ILD_TRANSPARENT = 0x0001; 

        /// <summary>
        /// Draws an image list item in the specified device context. 
        /// </summary>
        /// <param name="himl">
        /// Handle to the image list.
        /// </param>
        /// <param name="i">
        /// Index of the image to draw.
        /// </param>
        /// <param name="hdcDst">
        /// Handle to the destination device context. 
        /// </param>
        /// <param name="x">
        /// X-coordinate at which to draw within the specified device context.
        /// </param>
        /// <param name="y">
        /// Y-coordinate at which to draw within the specified device context.
        /// </param>
        /// <param name="dx">
        /// Width of the portion of the image to draw relative to the upper-left corner of the image. If dx and dy are zero, the function draws the entire image. The function does not ensure that the parameters are valid. 
        /// </param>
        /// <param name="dy">
        /// Height of the portion of the image to draw, relative to the upper-left corner of the image. If dx and dy are zero, the function draws the entire image. The function does not ensure that the parameters are valid. 
        /// </param>
        /// <param name="rgbBk">
        /// Background color of the image. 
        /// </param>
        /// <param name="rgbFg">
        /// Foreground color of the image.
        /// </param>
        /// <param name="fStyle">
        /// Drawing style and, optionally, the overlay image.
        /// </param>
        /// <returns>
        /// Returns nonzero if successful, or zero otherwise. 
        /// </returns>
        [DllImport("comctl32.dll")]
        public static extern bool ImageList_DrawEx(IntPtr himl, int i, IntPtr hdcDst, int x, int y, int dx, int dy, int rgbBk, int rgbFg, int fStyle);

        [DllImport("comctl32.dll")]
        public static extern bool ImageList_GetIconSize(IntPtr himl, out int cx, out int cy);


        #endregion 

        #region Member Variables

        public static void Draw(Graphics g, int x, int y, int width, int height, int index)
        {
            IntPtr handle = g.GetHdc();
            bool res = false; 

            try
            {
                res = ImageList_DrawEx(m_pImgHandle, index, handle, x, y, width, height, -1, -1, ILD_TRANSPARENT);
            }
            finally
            {
                g.ReleaseHdc(handle);
            }

        }

        // Used to store the handle of the system image list.
        private static IntPtr m_pImgHandle = IntPtr.Zero;

        // Flags whether we've already retrieved the image list handle or not.
        private static Boolean m_bImgInit = false;

        /// <summary>
        /// Image Width 
        /// </summary>
        private static int m_ImageWidth;

        /// <summary>
        /// Image Height 
        /// </summary>
        private static int m_ImageHeight;

        #endregion

        public static int ImageWidth
        {
            get { return m_ImageWidth; }
            set { m_ImageWidth = value; }
        }           

        public static int ImageHeight
        {
            get { return m_ImageHeight; }
            set { m_ImageHeight = value; }
        }
	
	
        #region Constants

        // TreeView message constants.
        private const UInt32 TVSIL_NORMAL = 0;
        private const UInt32 TVM_SETIMAGELIST = 4361;

        // ListView messages
        private const UInt32 LVM_FIRST = 0x1000;
        const UInt32 LVM_SETIMAGELIST = (LVM_FIRST + 3);
        const UInt32 LVSIL_SMALL = 1;
        const UInt32 LVSIL_NORMAL = 0;


        #endregion

        #region Private Methods

        /// <summary>
        /// Retrieves the handle of the system image list.
        /// </summary>
        public static void InitImageList()
        {
            // Only initialize once.
            if (m_bImgInit)
                throw new Exception("The system image list handle has already been retrieved.");

            // Retrieve the info for a fake file so we can get the image list handle.
            ShellAPI.SHFILEINFO shInfo = new ShellAPI.SHFILEINFO();
            ShellAPI.SHGFI dwAttribs =
                ShellAPI.SHGFI.SHGFI_USEFILEATTRIBUTES |
                ShellAPI.SHGFI.SHGFI_LARGEICON |
                ShellAPI.SHGFI.SHGFI_SYSICONINDEX;

            m_pImgHandle = ShellAPI.SHGetFileInfo(".txt", ShellAPI.FILE_ATTRIBUTE_NORMAL, out shInfo, (uint)Marshal.SizeOf(shInfo), dwAttribs);

            // Getting the dimensions of the images stored in the list
            ImageList_GetIconSize(m_pImgHandle, out m_ImageWidth, out m_ImageHeight);

            // Make sure we got the handle.
            if (m_pImgHandle.Equals(IntPtr.Zero))
                throw new Exception("Unable to retrieve system image list handle.");

            // Only allow one initialization.
            m_bImgInit = true;
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Sets the image list for the TreeView to the system image list.
        /// </summary>
        /// <param name="tvwHandle">The window handle of the TreeView control</param>
        public static void SetTVImageList(IntPtr tvwHandle)
        {
            InitImageList();
            // Int32 hRes = ShellAPI.SendMessage(tvwHandle, TVM_SETIMAGELIST, TVSIL_NORMAL, m_pImgHandle);

            // List View small
            // Int32 hRes = ShellAPI.SendMessage(tvwHandle, LVM_SETIMAGELIST, LVSIL_SMALL, m_pImgHandle);
            Int32 hRes = ShellAPI.SendMessage(tvwHandle, LVM_SETIMAGELIST, LVSIL_NORMAL, m_pImgHandle);

            if (hRes != 0)
                Marshal.ThrowExceptionForHR(hRes);
        }

        #endregion
    }
}
